package org.fin.minicat.container;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.fin.minicat.compile.Compiler;
import org.fin.minicat.compile.WebappClassLoader;
import org.fin.minicat.startup.Connector;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.rmi.ServerException;
import java.util.LinkedList;
import java.util.List;

@SuppressWarnings("ConstantConditions")
public class Server {

  private List<Service> services;

  public void start() {
    for (Service service : services) {
      service.start();
    }
  }

  @SuppressWarnings("unchecked")
  public void loadConfig() throws DocumentException, IOException {
    InputStream in = this.getClass().getClassLoader().getResourceAsStream("server.xml");

    SAXReader reader = new SAXReader();
    Document document = reader.read(in);

    Element root = document.getRootElement();
    List<Element> serviceElements = root.selectNodes("Service");
    services = new LinkedList<>();

    for (Element serviceElement : serviceElements) {
      Service service = new Service();
      services.add(service);

      // 读取并封装Connector
      List<Element> connectorElements = serviceElement.selectNodes("Connector");

      for (Element connectorElement : connectorElements) {
        int port = Integer.parseInt(connectorElement.attributeValue("port"));
        Connector connector = new Connector(port);
        connector.setService(service);
        service.addConnector(connector);
      }


      // 读取并创建Engine对象，并将Engine与Service关联
      Node engineElement = serviceElement.selectSingleNode("Engine");
      Engine engine = new Engine();
      service.setEngine(engine);

      // 封装Mapper对象，将Engine与Mapper关联
      Mapper mapper = new Mapper();
      engine.setMapper(mapper);

      // 读取并创建Host对象，并将Host对象存入Mapper中
      List<Element> hostElements = engineElement.selectNodes("Host");
      for (Element hostElement : hostElements) {
        // 获取appBase属性并验证路径是否正确
        String appBase = hostElement.attributeValue("appBase");
        File appBaseDir = new File(appBase);
        if (!appBaseDir.exists() || !appBaseDir.isDirectory()) {
          throw new RuntimeException("appBase配置错误，检查路径是否正确");
        }

        // 获取hostname，封装Host对象，存入mapper中
        String hostname = hostElement.attributeValue("name");
        Host host = new Host(hostname);
        host.setHostname(hostname);
        host.setAppBase(appBase);
        mapper.addHost(hostname, host);

        // 获取appBase下所有的目录，进行遍历
        for (File contextDir : appBaseDir.listFiles(File::isDirectory)) {

          // 对Context应用的java文件进行编译
          String sourceRoot = contextDir.getAbsolutePath() + "/src/";
          Compiler compiler = new Compiler(sourceRoot);
          compiler.compile();
          compiler.close();

          // 创建Context应用的classloader，并初始化Context容器对象，存入mapper中
          WebappClassLoader webappClassLoader = new WebappClassLoader(this.getClass().getClassLoader(), sourceRoot);
          String contextPath = "/" + contextDir.getName();
          Context context = new Context(contextPath, webappClassLoader);
          mapper.addContext(hostname, contextPath, context);


          // 读取并解析Context应用的web.xml，创建Wrapper容器对象和对应的Servlet，存入mapper中
          File webXml = new File(contextDir.getAbsolutePath() + "/web/WEB-INF/web.xml");
          if (webXml.exists() && webXml.isFile()) {
            document = reader.read(new FileInputStream(webXml));
            root = document.getRootElement();

            // 获取所有servlet配置标签，并进行遍历
            List<Element> servletElements = root.selectNodes("servlet");
            for (Element servletElement : servletElements) {

              // 获取servlet对应的servlet-mapping配置
              String servletName = servletElement.selectSingleNode("servlet-name").getStringValue();
              Element servletMapping = (Element) root.selectSingleNode("servlet-mapping[servlet-name='" + servletName + "']");

              // 找到对应的servlet-mapping配置，进一步获取其中的url-pattern和servlet-class属性
              // 封装wrapper对象，并实例化servlet对象
              // 最后将wrapper对象存入mapper中
              if (servletMapping != null) {
                String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
                String servletClass = servletElement.selectSingleNode("servlet-class").getStringValue();
                try {
                  Class<?> clz = context.getClassLoader().loadClass(servletClass);
                  Wrapper wrapper = new Wrapper(urlPattern, (Servlet) clz.getConstructor().newInstance());
                  mapper.addWrapper(hostname, contextPath, urlPattern, wrapper);
                } catch (Exception e) {
                  e.printStackTrace();
                }
              } else {
                throw new ServerException(servletName + " 对应的servlet-mapping配置不存在");
              }
            }
          }else {
            throw new ServerException("web.xml不存在或者存放路径不正确");
          }
        }

      }
    }


  }

}
